import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import java.awt.Insets;
import java.awt.datatransfer.*;
import java.io.IOException;

import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextArea;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;
import javax.swing.JApplet;

import javax.jnlp.*;


public class QuestCodeApplet extends JApplet implements ActionListener{

	private static final long serialVersionUID = -8400925962221843818L;
	private JPanel mainPanel = new JPanel();
	private JTextArea mainText = new JTextArea(25, 25);
	private JScrollPane jscrMain = new JScrollPane(mainText,
            JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
            JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
	private JTextArea outputText = new JTextArea(25, 25);
	private JScrollPane jscrOutput = new JScrollPane(outputText,
            JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
            JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
	private JButton pasteButton = new JButton("Paste");
	private JButton monListButton = new JButton("{{MonsterList}}");
	private JButton rewardsButton = new JButton("==Rewards==");
	private JButton formatButton = new JButton("Format");
	private JButton copyButton = new JButton("Copy all");
	private JButton clearButton = new JButton("Clear");
	private JButton angleButton = new JButton("«»");
	private JButton headingButton = new JButton("==H==");
	private JButton ruleButton = new JButton("----");
	private JButton undoButton = new JButton("Undo");
	private JButton redoButton = new JButton("Redo");
	private JLabel wrapLabel = new JLabel("Word wrap:");
	private JRadioButton wrapOn = new JRadioButton("On", false);
	private JRadioButton wrapOff = new JRadioButton("Off", true);
	private ButtonGroup wrapToggle = new ButtonGroup();
	private UndoManager undoManager = new UndoManager();
	private ClipboardService cbs;
	private String prevLineType = "";
	private boolean isList = false;
	
	public void init()
	{
		try {
            SwingUtilities.invokeAndWait(new Runnable() {
                public void run() {
                    createGUI();
                }
            });
		}
		catch (Exception e) { 
            System.err.println("createGUI didn't complete successfully");
            e.printStackTrace();
        }
	}

	private void createGUI()
	{
		outputText.setEditable(false);
		clearButton.setToolTipText("Clear the input area");
		pasteButton.setToolTipText("Paste the contents of the clipboard into the input area");
		monListButton.setToolTipText("Add an empty {{MonsterList}} template");
		rewardsButton.setToolTipText("Add a ==Rewards== header");
		angleButton.setToolTipText("Enclose the selected text in «double angle brackets»");
		headingButton.setToolTipText("Turn the selected text into a level 2 heading or add one level to an existing heading");
		ruleButton.setToolTipText("Add a horizontal rule");
		formatButton.setToolTipText("Generate the wikitext");
		copyButton.setToolTipText("Copy the formatted text to the clipboard");
		
		wrapToggle.add(wrapOn);
		wrapToggle.add(wrapOff);
		
		mainText.setWrapStyleWord(true);
		outputText.setWrapStyleWord(true);

		this.setContentPane(mainPanel);
		this.setName("Rhowena's Quest Wikicode Generator 1.0");
		
		mainText.getDocument().addUndoableEditListener(undoManager);
		
		try {
			cbs = (ClipboardService)ServiceManager.lookup("javax.jnlp.ClipboardService");
		} catch (UnavailableServiceException e) {
			cbs = null;
			e.printStackTrace();
		}
		
		mainPanel.setLayout(new GridBagLayout());
		GridBagConstraints c = new GridBagConstraints();
		
	    c.anchor = GridBagConstraints.LINE_START;
		Insets inset0 = new Insets(0, 0, 0, 0);
		
		c.insets = inset0;
		c.gridx = 0;
		c.gridy = 0;
		c.gridwidth = 1;
		c.weightx = 0.0;
	    mainPanel.add(pasteButton, c);
	    
	    c.insets = inset0;
	    c.gridx = 1;
	    c.gridy = 0;
	    c.gridwidth = 1;
	    c.weightx = 0.0;
	    mainPanel.add(headingButton, c);
	    
	    c.insets = inset0;
	    c.gridx = 2;
	    c.gridy = 0;
	    c.gridwidth = 1;
	    c.fill = GridBagConstraints.HORIZONTAL;
	    c.weightx = 0.0;
	    mainPanel.add(ruleButton, c);
	    
	    c.insets = inset0;
	    c.gridx = 3;
	    c.gridy = 0;
	    c.fill = GridBagConstraints.NONE;
	    c.gridwidth = 1;
	    c.weightx = 0.5;
	    mainPanel.add(angleButton, c);
	    
	    c.insets = inset0;
	    c.gridx = 0;
	    c.gridy = 1;
	    c.gridwidth = 2;
	    c.fill = GridBagConstraints.HORIZONTAL;
	    c.weighty = 0.0;
	    c.weightx = 0.0;
	    mainPanel.add(monListButton, c);
	    
	    c.gridx = 2;
	    c.gridy = 1;
	    c.gridwidth = 2;
	    c.weighty = 0.0;
	    c.weightx = 0.0;
	    c.fill = GridBagConstraints.NONE;
	    mainPanel.add(rewardsButton, c);
		
	    c.gridx = 0;
	    c.gridy = 2;
	    c.gridwidth = 4;
	    c.weightx = 0.0;
	    c.fill = GridBagConstraints.BOTH;
	    c.ipadx = 300;
	    c.ipady = 400;
	    c.weighty = 1.0;
	    mainPanel.add(jscrMain, c);
	    
	    c.gridx = 0;
	    c.gridy = 4;
	    c.gridwidth = 1;
	    c.fill = GridBagConstraints.HORIZONTAL;
	    c.ipadx = 0;
	    c.ipady = 0;
	    c.weighty = 0.0;
	    c.weightx = 0.0;
	    mainPanel.add(clearButton, c);
	    
	    c.gridx = 1;
	    c.gridy = 4;
	    c.gridwidth = 1;
	    c.fill = GridBagConstraints.HORIZONTAL;
	    c.ipadx = 0;
	    c.ipady = 0;
	    c.weighty = 0.0;
	    c.weightx = 0.0;
	    mainPanel.add(undoButton, c);
	    
	    c.gridx = 2;
	    c.gridy = 4;
	    c.gridwidth = 1;
	    c.fill = GridBagConstraints.NONE;
	    c.ipadx = 0;
	    c.ipady = 0;
	    c.weighty = 0.0;
	    c.weightx = 0.0;
	    mainPanel.add(redoButton, c);
	    
	    c.gridx = 5;
	    c.gridy = 1;
	    c.gridwidth = 1;
	    c.gridheight = 1;
	    c.weightx = 0.0;
	    c.weighty = 0.0;
		mainPanel.add(formatButton, c);
		
		c.gridx = 6;
		c.gridy = 1;
		c.gridwidth = 2;
		c.gridheight = 1;
		c.weighty = 0.0;
		c.weightx = 0.0;
		c.anchor = GridBagConstraints.LINE_START;
		c.fill = GridBagConstraints.NONE;
		mainPanel.add(copyButton, c);
		
		c.gridx = 5;
		c.gridy = 2;
		c.gridwidth = 3;
		c.gridheight = 2;
		c.fill = GridBagConstraints.BOTH;
		c.ipadx = 300;
		c.ipady = 400;
	    mainPanel.add(jscrOutput, c);
	    
	    c.gridx = 5;
	    c.gridy = 4;
	    c.gridwidth = 1;
		c.gridheight = 1;
		c.fill = GridBagConstraints.NONE;
		c.ipadx = 0;
		c.ipady = 0;
		c.weightx = 0;
		c.weighty = 0;
		mainPanel.add(wrapLabel, c);
		
		c.gridx = 6;
	    c.gridy = 4;
	    mainPanel.add(wrapOn, c);
	    
	    c.gridx = 7;
	    c.gridy = 4;
	    c.weightx = 0.5;
	    mainPanel.add(wrapOff, c);

		
		clearButton.addActionListener(this);
		pasteButton.addActionListener(this);
		monListButton.addActionListener(this);
		rewardsButton.addActionListener(this);
		angleButton.addActionListener(this);
		headingButton.addActionListener(this);
		ruleButton.addActionListener(this);
		formatButton.addActionListener(this);
		copyButton.addActionListener(this);
		undoButton.addActionListener(this);
		redoButton.addActionListener(this);
		wrapOn.addActionListener(this);
		wrapOff.addActionListener(this);
		
		this.validate();
	}

	
	
	private String FormatLine(String line)
	{
		if (line.length() > 0)
  	    {
	        int indent = 0;
	        String lineType = "";
            for (int i = 0; i < line.length(); i++)
            {
                if (line.charAt(i) == ':') indent++;
                else break;
            }
	        String indentString = line.substring(0, indent);
	        String lineTrue = line.substring(indent);
	        lineTrue = stripWhitespace(lineTrue);
	        int e = 0;

	        char c1 = lineTrue.charAt(0);
	        if (c1 == '=' || c1 == '*' || c1 == '{' || c1 == '|' || c1 == '}' || c1 == '-')
	        {
	            lineType = "Other";
	        }
	        else if (c1 > '0' && c1 <= '9') lineType = "Battle";
	        else if ((lineTrue.length() >= 9 && line.substring(0, 9).equalsIgnoreCase("Full Heal"))
	        		|| (lineTrue.length() >= 18 && line.substring(0, 18).equalsIgnoreCase("Optional Full Heal")))
	        	lineType = "Battle";
	        else if (c1 == '«' && !lineTrue.substring(0, 5).equals("«You»")) lineType = "Other";
	        else
	        {
	            for (int i = 0; i < lineTrue.length(); i++)
	            {
	                char a = lineTrue.charAt(i);
	                if (a == ':')
	                {
	                    e++;
	                    break;
	                }
	                e++;
	            } // extract loop 1
	        
	            if (e == lineTrue.length())
	            {
	        	    if (prevLineType.equals("Battle") || prevLineType.equals("BattleLevel"))
	        	    {
	        	    	lineType = "Battle";
	        	    	lineTrue = linkParen(lineTrue);
	        	    	lineTrue = lineTrue.substring(0, lineTrue.length() - 5);
	        	    }
	        	    else
	          		    lineType = "Direction";
	            }
	            else if (line.substring(0, 5).equals("Level")) lineType = "BattleLevel";
	            else lineType = "Dialogue";
	        }

	        String printLine = "";
	        if (lineType.equals("Battle")) printLine = printBattle(lineTrue);
	        else if (lineType.equals("BattleLevel")) printLine = printBattleLevel(lineTrue, e);
	        else if (lineType.equals("Dialogue")) printLine = printDialogue(lineTrue, e);
	        else if (lineType.equals("Direction")) printLine = printDirection(lineTrue);
	        else if (lineType.equals("Other")) printLine = lineTrue;
	        prevLineType = lineType;
	        return (indentString + printLine);
	      }
		else
		{
			prevLineType = "";
			return line;
		}
	}
	private String printBattle (String line)
	{
	    String printLine = line + " <br>";
	    return printLine;
	}
	private String printBattleLevel (String line, int e)
	{
	    String levelString = line.substring(0,e);
	    String printLine = "<u>" + levelString + "</u>" + " " + linkParen(line.substring(e + 1));
	    return printLine;
	}
	private String printDialogue (String line, int e)
	{
	    String nameString = line.substring(0,e);
	    String printLine = "'''" + nameString + "'''" + line.substring(e) + " <br>";
	    return printLine;
	}
	private String printDirection (String line)
	{
	    String printLine = "''" + line + "''";
	    return printLine;
	}
	private String linkParen(String line)
	{
		if (line.length() > 0)
		{
			int f = 0;
			for (int i = 0; i < line.length(); i++)
			{
				char a = line.charAt(i);
				if (i > 0 && a >= '0' && a <= '9' && line.charAt(i - 1) == '(')
				{
					if (f > 1) f -= 2;
					break;
				}
				else if (line.charAt(i) == '}') break;
				f++;
			}
			if (f > 0) line = "[[" + line.substring(0,f) + "]]" + line.substring(f) + " <br>";
		}
		return line;
	}
	private String stripWhitespace(String line)
	{
		int w = 0;
		for (int i = 0; i < line.length(); i++)
		{
			if (line.charAt(i) != ' ' && line.charAt(i) != '\t') break;
			w++;
		}
		int f = line.length();
		for (int i = line.length() - 1; i > 0; i--)
		{
			if (line.charAt(i) != ' ' && line.charAt(i) != '\t') break;
			f--;
		}
		line = line.substring(w, f);
		return line;
	}
	private String listFormat (String line)
	{
		if (line.length() > 2 && line.substring(0, 2).equals("==") && line.charAt(2) != '=')
		{
			isList = false;
			return line;
		}
		if (line.length() > 0 && line.charAt(0) == '=')
			return line;
		for (int i = 0; i < line.length(); i++)
			if (line.charAt(i) == '}') isList = false;
		if (line.length() > 0 && line.charAt(0) == '|')
		{
			if (line.substring(1, 4).equalsIgnoreCase("mon"))
			{
				int begin = 0;
				for (int i = 0; i < line.length(); i++)
				{
					begin++;
					if (line.charAt(i) == '=') break;
				}
				String lineTrue = line.substring(begin);
				lineTrue = stripWhitespace(lineTrue);
				lineTrue = linkParen(lineTrue);
				return line.substring(0, begin) + lineTrue;
			}
			else return line;
		}
		else
		{
			line = linkParen(line);
			return line;
		}
	}

	@Override
	public void actionPerformed(ActionEvent ev) {
		if (ev.getSource() == clearButton)
		{
			mainText.selectAll();
			mainText.replaceSelection("");
		}
		else if (ev.getSource() == pasteButton)
		{
			String s = "";
			if (cbs != null)
			{
				try {
					s = (String)cbs.getContents().getTransferData(java.awt.datatransfer.DataFlavor.stringFlavor);
					mainText.replaceSelection(s);
				} catch (UnsupportedFlavorException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		else if (ev.getSource() == monListButton)
			mainText.replaceSelection("{{MonsterList\n|lvl=Level \n|mon=\n}}\n");
		else if (ev.getSource() == rewardsButton)
			mainText.replaceSelection("==Rewards==\n");
		else if (ev.getSource() == angleButton)
		{
			if (mainText.getSelectedText() != null)
				mainText.replaceSelection("«" + mainText.getSelectedText() + "»");
			else mainText.replaceSelection("«»");
		}
		else if (ev.getSource() == headingButton)
		{
			if (mainText.getSelectionStart() > 0) mainText.setSelectionStart(mainText.getSelectionStart() - 1);
			String selection = mainText.getSelectedText();
			if (selection.charAt(0) == '\n')
			{
				mainText.setSelectionStart(mainText.getSelectionStart() + 1);
				selection = mainText.getSelectedText();
			}
			if (selection.charAt(0) == '=')
				mainText.replaceSelection("=" + selection + "=");
			else
				mainText.replaceSelection("==" + selection + "==");
		}
		else if (ev.getSource() == ruleButton)
			mainText.replaceSelection("\n----\n\n");
		else if (ev.getSource() == formatButton)
		{
			outputText.selectAll();
			outputText.replaceSelection("");
			outputText.append("{{Quest\n|loc=\n|bbh=\n|chain=\n|prev=\n|next=\n}}\n\n");
			for (String line : mainText.getText().split("\\n"))
			{
				line = stripWhitespace(line);
				if (isList)
					outputText.append(listFormat(line) + '\n');
				else
				{
					if (line.equals("==Rewards==") ||
							(line.length() >= 13 && line.substring(0, 13).equals("{{MonsterList")))
					{
						isList = true;
						outputText.append(line + '\n');
					}
					else
						outputText.append(FormatLine(line) + '\n');
				}
			}
		}
		else if (ev.getSource() == copyButton)
		{
			outputText.selectAll();
			if (cbs != null)
			{
				StringSelection s = new StringSelection(mainText.getSelectedText());
				cbs.setContents(s);
			}
		}
		else if (ev.getSource() == undoButton)
		{
			try {
				undoManager.undo();
			} catch (CannotUndoException e) {
			}
		}
		else if (ev.getSource() == redoButton)
		{
			try {
				undoManager.redo();
			} catch (CannotRedoException e) {
			}
		}
		else if (ev.getSource() == wrapOn)
		{
			mainText.setLineWrap(true);
			outputText.setLineWrap(true);
		}
		else if (ev.getSource() == wrapOff)
		{
			mainText.setLineWrap(false);
			outputText.setLineWrap(false);
		}
	}


}
